/*
   This file is part of the 'Let's Do Stuff Together' project
   http://code.google.com/p/dostufftogether/

   Copyright 2010 Christoph Fuchs, Stefan Thaler

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package org.sti2.letsdostuff;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.sti2.letsdostuff.configuration.ServerConfiguration;
import org.sti2.letsdostuff.location.ActivityLocationListener;
import org.sti2.letsdostuff.location.MyGoogleMaps;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;

import com.google.android.maps.GeoPoint;

/**
 * 
 * Android activity to create an activity (<i>not</i> an Android activity, but
 * an activity in the sense of something that can be done together, hence the
 * central object of our application) and set it to the activity server.
 * 
 * The activity is created by invoking the REST defined interface. For creating
 * an activity the interface looks as follows
 * 
 * <blockquote>http://example.com/ActivityServer/activity/?title=TITLE&
 * description
 * =PLAIN_TEXT&long=LONGITUDE&lat=LATITUDE&alt=ALTITUDE&startTime=TIMESTAMP
 * &endTime=TIMESTAMP</blockquote>
 * 
 * @author Christoph 'Gigi' Fuchs
 * 
 */
public class CreateActivity extends Activity {

	/** The Constant TIME_DIALOG_ID. */
	private static final int TIME_DIALOG_ID = 0;
	
	/** The Constant DATE_DIALOG_ID. */
	protected static final int DATE_DIALOG_ID = 1;
	
	protected static final int MAP_REQUEST_CODE = 1337;
	
	
	private TextView mTimeDisplay;
	private Button mPickTime;
	private int mHour;
	private int mMinute;
	private TextView mDateDisplay;
	private Button mPickDate;
	private int mYear;
	private int mMonth;
	private int mDay;
	private Button mNow;
	private Button mToday;
	private CheckBox mCheckBox;
	private Button mMap;
	private LocationManager mlocManager;
	private ActivityLocationListener mlocListener;
	private Button mOk;
	private TextView mTitle;
	private TextView mDescripition;

	private double mLatitude;

	private double mLongitude;

	private CheckBox mUseCurrentLocation;

	private String mAddressName;

	private EditText mAddressField;

	private Location lastKnownLocation;

	private CheckBox mCatFood;

	private CheckBox mCatOther;

	private CheckBox mCatPlays;

	private CheckBox mCatSights;

	private CheckBox mCatSport;

	private String mCategoriesList;

	/* (non-Javadoc)
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.create);
        
        // Title and description
        mTitle = (TextView) findViewById(R.id.text_createTitle);
        mDescripition = (TextView) findViewById(R.id.text_createDescription);
        
        // Date and Time related stuff
        createDateTimeListeners();
        setCurrentTime();
        setCurrentDay();
        
        // Location related stuff
        mMap = (Button) findViewById(R.id.button_map);
        mMap.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("View", "Switching to Google maps view");
				Intent mapsIntent = new Intent(v.getContext(), MyGoogleMaps.class);
				startActivityForResult(mapsIntent, MAP_REQUEST_CODE);
			}
		});
        
        mAddressField = (EditText) findViewById(R.id.text_create_map_address);
        
        mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
       	mlocListener = new ActivityLocationListener();
       	mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        
       	lastKnownLocation = mlocManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
       	
       	mCheckBox = (CheckBox) findViewById(R.id.checkbox_location);
        mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				if (isChecked) {
					mMap.setEnabled(false);
					String addressNameFromGeoCoder = MyGoogleMaps
							.getAddressNameFromGeoCoder(
									getBaseContext(), mlocListener
											.getLatitude(), mlocListener
											.getLongitude());
					Log.v("GeoCoder", "Got address name for current position: " + addressNameFromGeoCoder);
					mAddressField.setText(addressNameFromGeoCoder);
				} else {
					mMap.setEnabled(true);
				}
			}
		});
       	
        /*
         * Categories
         */
        mCatFood = (CheckBox) findViewById(R.id.checkbox_catFood);
        mCatOther = (CheckBox) findViewById(R.id.checkbox_catOther);
        mCatPlays = (CheckBox) findViewById(R.id.checkbox_catPlays);
        mCatSights = (CheckBox) findViewById(R.id.checkbox_catSights);
        mCatSport = (CheckBox) findViewById(R.id.checkbox_catSport);
        
        StringBuilder sb = new StringBuilder();
        
        if (mCatFood.isChecked())
        	sb.append(mCatFood.getText().toString()).append(", ");
        if (mCatOther.isChecked())
        	sb.append(mCatOther.getText().toString()).append(", ");
        if (mCatPlays.isChecked())
        	sb.append(mCatPlays.getText().toString()).append(", ");
        if (mCatSights.isChecked())
        	sb.append(mCatSights.getText().toString()).append(", ");
        if (mCatSport.isChecked())
        	sb.append(mCatSport.getText().toString()).append(", ");
        
        mCategoriesList = sb.toString();
        
//        /*
//         * Duration
//         */
//        Spinner s = (Spinner) findViewById(R.id.spinner_createDuration);
//        ArrayAdapter adapter = ArrayAdapter.createFromResource(
//                this, R.array.durations, android.R.layout.simple_spinner_item);
//        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//        s.setAdapter(adapter);
        
       	// The OK button
       	mOk = (Button) findViewById(R.id.button_createOk);
       	mOk.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("View", "Submitting activity to server.");
				doGeoCoding();
				submitToServer();
			}
		});
       	
        // display the current date
        updateDisplay();
    }

	/**
	 * If the user simply typed in a string, find the according GeoPoint.
	 */
	protected void doGeoCoding() {
		
		Geocoder geoCoder = new Geocoder(getBaseContext());
		GeoPoint point = null;
		try {
			List<Address> addresses = geoCoder.getFromLocationName(mAddressField.getText().toString(), 1);
			if (addresses.size() > 0) {
				point = new GeoPoint(
	                    (int) (addresses.get(0).getLatitude() * 1E6), 
	                    (int) (addresses.get(0).getLongitude() * 1E6));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		Log.v("GeoCoding", "User typed in " + mAddressField.getText() + ". Got GeoPoint " + point);
		
		if (point == null) {
			Log.e("GeoCoding", "Unable to geoCode current location.");
			return;
		}
		
		mLongitude = point.getLongitudeE6() / 1E6;
		mLatitude = point.getLatitudeE6() / 1E6;
	}

	/* (non-Javadoc)
	 * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		Log.v("Create", "onActivityResult fired with request code " + requestCode + " and result code " + resultCode);
		
		switch (requestCode) {
		case (MAP_REQUEST_CODE): {
			if (resultCode == Activity.RESULT_OK) {
				Log.v("Create", "Retrieving GeoLocation from Map");
				mLatitude = data
						.getIntExtra(MyGoogleMaps.GEO_LATITUDE_E6, 0) / 1E6;
				mLongitude = data.getIntExtra(MyGoogleMaps.GEO_LONGITUDE_E6,
						0) / 1E6;
				mAddressName = data.getStringExtra(MyGoogleMaps.GEO_ADDRESS);
				mAddressField.setText(mAddressName);
				
				Log.v("Create", "Longitude: " + mLongitude + ", Latitude: " + mLatitude + ", Address Name: " + mAddressName);
				
			}
			break;
		}
		}
	}
	
	/**
	 * Creates the date and time listeners.
	 */
	private void createDateTimeListeners() {
		// capture our View elements (time and date)
        mTimeDisplay = (TextView) findViewById(R.id.label_timeDisplay);
        mPickTime = (Button) findViewById(R.id.button_pickTime);

        mDateDisplay = (TextView) findViewById(R.id.label_dateDisplay);
        mPickDate = (Button) findViewById(R.id.button_pickDate);
        
        mNow = (Button) findViewById(R.id.button_Now);
        mToday = (Button) findViewById(R.id.button_Today);
        
        // add a click listener to the buttons
        mPickTime.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                showDialog(TIME_DIALOG_ID);
            }
        });
        
        mPickDate.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                showDialog(DATE_DIALOG_ID);
            }
        });
        
        mNow.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				setCurrentTime();
				updateDisplay();
			}
		});
        
        mToday.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				setCurrentDay();
				updateDisplay();
			}
		});
        
        mUseCurrentLocation = (CheckBox) findViewById(R.id.checkbox_location);
	}
	
	/**
	 * Sets the current time.
	 */
	private void setCurrentTime() {
		// get the current time
        final Calendar c = Calendar.getInstance();
        mHour = c.get(Calendar.HOUR_OF_DAY);
        mMinute = c.get(Calendar.MINUTE);
	}
	
	/**
	 * Sets the current day.
	 */
	private void setCurrentDay() {
		// get the current date
        final Calendar c = Calendar.getInstance();
        mYear = c.get(Calendar.YEAR);
        mMonth = c.get(Calendar.MONTH);
        mDay = c.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * Submit the activity to the server so he can create and store it. Using
	 * HTTP POST.
	 */
	private void submitToServer() {
		DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
		
		try {
			Log.i("HTTP", "Encoding URL to utf-8...");
			String createActivityURL = generateCreateActivityURL();
			HttpPost httpPost = new HttpPost(createActivityURL);
			Log.i("HTTP", "Trying to build up HTTP POST request...");
			Log.i("HTTP", createActivityURL);
			HttpResponse response = defaultHttpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			
			Log.i("HTTP", "Server response " + statusCode);
			
			if (statusCode == HttpStatus.SC_OK) {
				Log.i("HTTP", "Server responded with " + HttpStatus.SC_OK + " (OK)");
				
				Toast toast = Toast.makeText(this.getApplicationContext(), "Successfully created Activity", Toast.LENGTH_LONG );
				toast.show();
				
				Intent homeScreen = new Intent(this.getApplicationContext(), LetsDoStuff.class);
				startActivity(homeScreen);
			}
		} catch (ClientProtocolException e) {
			Toast toast = Toast.makeText(this.getApplicationContext(), "Could not connect to server. Reason: " + e.getMessage(), Toast.LENGTH_SHORT );
			toast.show();
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			Toast toast = Toast.makeText(this.getApplicationContext(), "Encoding error. Reason: " + e.getMessage(), Toast.LENGTH_SHORT );
			toast.show();
			e.printStackTrace();
		} catch (IOException e) {
			Toast toast = Toast.makeText(this.getApplicationContext(), "I/O error. Reason: " + e.getMessage(), Toast.LENGTH_SHORT );
			toast.show();
			e.printStackTrace();
		}
	}

	/**
	 * Build a URL used in a HTTP POST request to create an activity. For the
	 * REST protocol specification see the REST interace specification document.
	 * 
	 * The general interface looks as follows:
	 * 
	 * <blockquote>http://example.com/ActivityServer/activity/?title=TITLE&description=PLAIN_TEXT&long=LONGITUDE&lat=LATITUDE&alt=ALTITUDE&startTime=TIMESTAMP&endTime=TIMESTAMP</blockquote>
	 * 
	 * @return the string
	 */
	private String generateCreateActivityURL() {
		Timestamp startTime = new Timestamp(mYear, mMonth, mDay, mHour, mMinute, 0, 0);
		Timestamp endTime = startTime;
		
		StringBuffer sb =  new StringBuffer();
		sb.append(ServerConfiguration.ACTIVITY_SERVER);
		sb.append("/activity/");
		sb.append("?title=").append(URLEncoder.encode(mTitle.getText().toString()));
		sb.append("&description=").append(URLEncoder.encode(mDescripition.getText().toString()));
		
		if (mUseCurrentLocation.isChecked()) {
			if (lastKnownLocation != null) {
				sb.append("&long=").append(lastKnownLocation.getLongitude());
				sb.append("&lat=").append(lastKnownLocation.getLatitude());
				sb.append("&alt=").append(lastKnownLocation.getAltitude());
			} else {
				sb.append("&long=").append(mlocListener.getLongitude());
				sb.append("&lat=").append(mlocListener.getLatitude());
				sb.append("&alt=").append(mlocListener.getAltitude());
			}
		} else {
			sb.append("&long=").append(mLongitude);
			sb.append("&lat=").append(mLatitude);
			sb.append("&alt=").append(0);
		}
		sb.append("&startTime=").append(startTime.getTime());
		sb.append("&endTime=").append(endTime.getTime());
		sb.append("&category=").append(mCategoriesList);
		
		return sb.toString();
	}
	
	/* (non-Javadoc)
	 * @see android.app.Activity#onCreateDialog(int)
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
	    switch (id) {
	    case TIME_DIALOG_ID:
	        return new TimePickerDialog(this,
	                mTimeSetListener, mHour, mMinute, false);
	    case DATE_DIALOG_ID:
			return new DatePickerDialog(this, mDateSetListener, mYear, mMonth,
					mDay);
	    }
	    return null;
	}
	
	private void updateDisplay() {
		mTimeDisplay.setText(new StringBuilder().append(pad(mHour)).append(":")
				.append(pad(mMinute)));
	    
		// month + 1 since jan = 00
		mDateDisplay.setText(new StringBuilder().append(pad(mDay)).append(".")
				.append(pad(mMonth+1)).append(".").append(mYear));
		
		if (isTimeSetToNow()) {
			mNow.setEnabled(false);
		} else {
			mNow.setEnabled(true);
		}
		
		if (isDateSetToToday()) {
			mToday.setEnabled(false);
		} else {
			mToday.setEnabled(true);
		}
		
	}
	
	/**
	 * Checks if time is set to now.
	 * 
	 * @return true, if time is set to now
	 */
	private boolean isTimeSetToNow() {
		final Calendar c = Calendar.getInstance();
        int checkHour = c.get(Calendar.HOUR_OF_DAY);
        int checkMinute = c.get(Calendar.MINUTE);

        return (checkHour == mHour) && (checkMinute == mMinute);
	}

	/**
	 * Checks if date is set to today.
	 * 
	 * @return true, if date is set to today
	 */
	private boolean isDateSetToToday() {
		final Calendar c = Calendar.getInstance();
		// get the current date
        int checkYear = c.get(Calendar.YEAR);
        int checkMonth = c.get(Calendar.MONTH);
        int checkDay = c.get(Calendar.DAY_OF_MONTH);
        
        return (checkYear == mYear) && (checkMonth == mMonth) && (checkDay == mDay);
	}

	private static String pad(int c) {
	    if (c >= 10)
	        return String.valueOf(c);
	    else
	        return "0" + String.valueOf(c);
	}
	
	// the callback received when the user "sets" the time in the dialog
	private TimePickerDialog.OnTimeSetListener mTimeSetListener =
	    new TimePickerDialog.OnTimeSetListener() {
	        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
	            mHour = hourOfDay;
	            mMinute = minute;
	            updateDisplay();
	        }
	    };
	    
	 // the callback received when the user "sets" the date in the dialog
 	private DatePickerDialog.OnDateSetListener mDateSetListener =
	    new DatePickerDialog.OnDateSetListener() {
			@Override
			public void onDateSet(DatePicker view, int year, int monthOfYear,
					int dayOfMonth) {
				mYear = year;
	            mMonth = monthOfYear;
	            mDay = dayOfMonth;
	            updateDisplay();
			}
	    };
	    
}